/************************************************
 * Author       :   XXY
 * Blog         :   https://www.cnblogs.com/jzyl
 * Gitee        :   https://gitee.com/xiaobaichong
 * Email        :   1047185209@QQ.com
 * FileName     :   ComponentIDE.cs
 * CreateData   :   2023/4/29 16:08:54
 * UnityVersion :   2020.3.33f1c2
 * Description  :   Hotfix 数据组件
************************************************/
#pragma warning disable CS0414
using Sirenix.OdinInspector;
using System;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using Object = UnityEngine.Object;
using Sirenix.Utilities;
using System.Reflection;
using UnityEngine.UI;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Main
{
    /// <summary>
    /// Hotfix ECS 数据生成组件
    /// </summary>
    [ExecuteAlways]
    [HideMonoScript]
    [DisallowMultipleComponent]
    public class ComponentIDE : SerializedMonoBehaviour
    {
#if UNITY_EDITOR
        [HideInInspector]
        public bool isError = false;
        [Button("预览"), InfoBox("字段不能为空!", InfoMessageType.Error, "isError")]
        private void Preview()
        {
            GenerateScriptPreviewWindow.ShowWindow(CodeStr());
        }
        // 字段转 代码
        private string CodeStr()
        {
            string tab = " ";
            string blank = " ";
            string newLine = "\n";
            string Modifier = "public";
            string prefix = "//";
            string end = ";";
            string separate = $"/************************华丽的分界线*************************/";
            StringBuilder script = new StringBuilder();
            script.Append(newLine + tab + separate + newLine);
            foreach (var item in valueItems)
            {
                if (!item.Description.IsNullOrWhitespace())
                {
                    script.Append(tab + prefix + blank + item.Description + newLine);
                }
                script.Append(tab + Modifier + blank + item.type + blank + item.FieldName + end + newLine);
            }
            script.Append(newLine);
            script.Append(newLine);
            script.Append(newLine);
            script.Append(tab + separate + newLine);
            foreach (var item in referenceItems)
            {
                if (!item.Description.IsNullOrWhitespace())
                {
                    script.Append(tab + prefix + blank + item.Description + newLine);
                }
                script.Append(tab + Modifier + blank + item.type + blank + item.FieldName + end + newLine);
            }
            script.Append(newLine);
            script.Append(newLine);
            script.Append(newLine);
            script.Append(tab + separate + newLine);
            foreach (var item in valueCollectionItems)
            {
                if (!item.Description.IsNullOrWhitespace())
                {
                    script.Append(tab + prefix + blank + item.Description + newLine);
                }
                script.Append(tab + Modifier + blank + item.type + blank + item.FieldName + end + newLine);
            }
            script.Append(newLine);
            script.Append(newLine);
            script.Append(newLine);
            script.Append(tab + separate + newLine);
            foreach (var item in referenceCollectionItems)
            {
                if (!item.Description.IsNullOrWhitespace())
                {
                    script.Append(tab + prefix + blank + item.Description + newLine);
                }
                script.Append(tab + Modifier + blank + item.type + blank + item.FieldName + end + newLine);
            }
            return script.ToString();
        }
#endif
        [Space(10)]
        [TabGroup("一般类型"), TableList(/*AlwaysExpanded = true,*/ DrawScrollView = true, ShowIndexLabels = true), HideLabel]
        public List<ComponentDataValueItem> valueItems = new List<ComponentDataValueItem>();

        [Space(10)]
        [TabGroup("Unity对象"), TableList(/*AlwaysExpanded = true, */DrawScrollView = false, ShowIndexLabels = true), HideLabel]
        public List<ComponentDataReferenceItem> referenceItems = new List<ComponentDataReferenceItem>();

        [Space(10)]
        [TabGroup("一般类型集合"), TableList(/*AlwaysExpanded = true,*/ DrawScrollView = false, ShowIndexLabels = true), HideLabel]
        public List<ComponentDataValueCollectionItem> valueCollectionItems = new List<ComponentDataValueCollectionItem>();

        [Space(10)]
        [TabGroup("Unity对象集合"), TableList(/*AlwaysExpanded = true, */DrawScrollView = false, ShowIndexLabels = true), HideLabel]
        public List<ComponentDataReferenceCollectionItem> referenceCollectionItems = new List<ComponentDataReferenceCollectionItem>();
#if UNITY_EDITOR
        /// <summary>
        /// 这不是每帧更新
        /// 当属性面板改动是触发
        /// DOTO:是这样吗???
        /// </summary>
        private void Update()
        {
            // 更新
            foreach (var item in referenceCollectionItems)
            {
                item.Update();
            }


            isError = false;
            // 判断字段是否为空
            // TODO : 字段是否重复
            foreach (var item in valueItems)
            {
                if (item.FieldName.IsNullOrWhitespace())
                {
                    isError = true;
                    return;
                }
            }
            foreach (var item in referenceItems)
            {
                if (item.FieldName.IsNullOrWhitespace())
                {
                    isError = true;
                    return;
                }
            }
            foreach (var item in valueCollectionItems)
            {
                if (item.FieldName.IsNullOrWhitespace())
                {
                    isError = true;
                    return;
                }
            }
            foreach (var item in referenceCollectionItems)
            {
                if (item.FieldName.IsNullOrWhitespace())
                {
                    isError = true;
                    return;
                }
            }
        }
#endif
        #region Utility
        /// <summary>
        /// 通过名称返回字段当前值
        /// </summary>
        /// <typeparam name="T">支持的类型</typeparam>
        /// <param name="name">字段名称</param>
        /// <returns></returns>
        public T GetValue<T>(string name)/*where T: struct*/
        {
            ComponentDataValueItem item = valueItems.Where(item => item.FieldName == name).FirstOrDefault();
            if (item != null)
            {
                Type type = item.GetType();
                var field = type.GetFields(BindingFlags.Instance | BindingFlags.Public).Where(info => info.FieldType.FullName == item.type);
                var value = field.First();
                return (T)value.GetValue(item);
            }
            else
            {
                return default(T);
            }
        }
        /// <summary>
        /// 通过名称获取当前对象
        /// </summary>
        /// <typeparam name="T">Unity Object</typeparam>
        /// <param name="name">字段名称</param>
        /// <returns></returns>
        public T GetReference<T>(string name) where T : Object
        {
            ComponentDataReferenceItem item = referenceItems.Where(item => item.FieldName == name).FirstOrDefault();
            if (item != null)
            {
                return (T)item.@component;
            }
            else
            {
                return null;
            }

        }
        /// <summary>
        /// 通过名称获取当前值集合
        /// </summary>
        /// <typeparam name="T">获取的List<T>类型</typeparam>
        /// <param name="name">字段名称</param>
        /// <returns></returns>
        public List<T> GetValues<T>(string name)
        {
            ComponentDataValueCollectionItem item = valueCollectionItems.Where(item => item.FieldName == name).FirstOrDefault();
            if (item != null)
            {
                Type type = item.GetType();
                var field = type.GetFields(BindingFlags.Instance | BindingFlags.Public).Where(info => info.FieldType.FullName.Contains(item.type.Substring(5, item.type.Length - 6)));
                var value = field.First();
                return value.GetValue(item) as List<T>;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 通过名称获取Unity 对象集合
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public List<T> GetReferences<T>(string name) where T : Object
        {
            ComponentDataReferenceCollectionItem item = referenceCollectionItems.Where(item => item.FieldName == name).FirstOrDefault();
            if (item != null)
            {
                return item.components.Cast<T>().ToList();
            }
            else
            {
                return null;
            }
        }
        #endregion
    }
    /// <summary>
    /// 一般类型
    /// </summary>
    [Serializable]
    public class ComponentDataValueItem
    {
        #region 对象类型
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.Bool)]
        public bool boolValue;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.Int)]
        public int intValue;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.Float)]
        public float floatValue;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.Char)]
        public char charValue;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.String)]
        public string stringValue;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.Vector2)]
        public Vector2 vector2Value;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.Vector3)]
        public Vector3 vector3Value;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.Vector4)]
        public Vector4 vector4Value;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.Color)]
        public Color colorValue;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.Gradient)]
        public Gradient gradientValue;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValue", EnumValue.AnimationCurve)]
        public AnimationCurve animationcurveValue;

        [HorizontalGroup("其他类型/HorizontalGroup")]
        [HideLabel, ReadOnly]
        public string type = "类型";
        [HorizontalGroup("其他类型/HorizontalGroup")]
        [HideLabel, OnValueChanged("OnEnumValueChange")]
        public EnumValue enumValue;
        #endregion
        #region 生成字段
        [VerticalGroup("生成字段"), LabelText("字段名称:"), LabelWidth(60), Delayed, OnValueChanged("OnFieldNameChange")]
        public string FieldName;
        [VerticalGroup("生成字段"), LabelText("注释描述:"), LabelWidth(60)]
        public string Description;
        #endregion
#if UNITY_EDITOR
        #region 按钮
        //[TableColumnWidth(70, Resizable = false)]
        //[VerticalGroup("按钮")]
        //[Button("测试")]
        //private void Test()
        //{

        //}
        #endregion
        #region 事件
        private void OnEnumValueChange()
        {
            Type _type = enumValue.GetType();
            string name = Enum.GetName(_type, enumValue);
            FieldInfo field = _type.GetField(name);
            EnumValueTypeAttribute attribute = Attribute.GetCustomAttribute(field, typeof(EnumValueTypeAttribute)) as EnumValueTypeAttribute;
            type = attribute.TypeFullName;
            ClearOtherValues();
        }
        // 清空没有选择的字段集合
        private void ClearOtherValues()
        {
            foreach (var type in this.GetType().GetFields())
            {
                ShowIfAttribute show = type.GetCustomAttribute<ShowIfAttribute>(true);
                if (show != null && (EnumValue)show.Value != enumValue)
                {
                    type.SetValue(this, default);
                }
            }
        }
        private void OnFieldNameChange()
        {
            if (!Regex.IsMatch(FieldName, @"^[a-zA-Z_\u4e00-\u9fa5][a-zA-Z0-9_\u4e00-\u9fa5]*$"))
            {
                FieldName = "";
            }
        }
        [OnInspectorInit]
        private void CreateData()
        {
            // 开始显示初始化
            OnEnumValueChange();
        }
        #endregion
#endif
    }
    /// <summary>
    /// Unity 对象类型
    /// </summary>
    [Serializable]
    public class ComponentDataReferenceItem
    {
        private EnumObject enumObject = EnumObject.None;
        #region 对象类型
        [VerticalGroup("对象类型"), LabelWidth(22)]
        [HideLabel, OnValueChanged("OnObjectChange")]
        public Object @object;

        [HorizontalGroup("对象类型/HorizontalGroup")]
        [HideLabel, ReadOnly]
        public string type = "类型";
        [HorizontalGroup("对象类型/HorizontalGroup")]
        [HideLabel, OnValueChanged("OnComponentChange")]
        [ValueDropdown("GetComponents"), Required("请选择一个对象!")]
        public Object @component;
        #endregion
        #region 生成字段
        [VerticalGroup("生成字段"), LabelText("字段名称:"), LabelWidth(60), Delayed, OnValueChanged("OnFieldNameChange")]
        public string FieldName;
        [VerticalGroup("生成字段"), LabelText("注释描述:"), LabelWidth(60)]
        public string Description;
        #endregion
#if UNITY_EDITOR
        #region 按钮
        //[TableColumnWidth(70, Resizable = false)]
        //[VerticalGroup("按钮")]
        //[Button("测试")]
        //private void Test()
        //{

        //}
        #endregion
        #region 事件
        private void OnObjectChange()
        {
            // 判空
            if (@object == null)
            {
                type = "Null";
                @component = null;
                enumObject = EnumObject.None;
            }
            else
            {
                var t = @object.GetType();
                type = t.FullName;

                // 判断是否是Editor 对象类型
                if (type.Contains("UnityEditor"))
                {
                    type = "Null";
                    @component = null;
                    enumObject = EnumObject.EditorObject;
                }
                else
                {
                    // 判断是否是预制件对象
                    if (PrefabUtility.GetPrefabAssetType(@object) != PrefabAssetType.NotAPrefab)
                    {
                        enumObject = EnumObject.PrefabObject;
                    }
                    else
                    {
                        enumObject = EnumObject.UnityObject;
                    }
                    if (!HasComponent(@component))
                    {
                        @component = @object;
                    }
                    type = @component.GetType().FullName;
                }
            }
        }
        private void OnComponentChange()
        {
            if (@component != null)
            {
                type = @component.GetType().FullName;
                @object = @component;
            }
        }

        // 返回选中对象组件集合
        private IEnumerable<Object> GetComponents()
        {
            List<Object> objs = null;
            if (enumObject == EnumObject.PrefabObject)
            {
                objs = new List<Object>();
                objs.Add(@object);
            }
            else if (enumObject == EnumObject.UnityObject)
            {
                GameObject obj;
                if (@object.GetType().IsSubclassOf(typeof(Component)))
                {
                    obj = (@object as Component).gameObject;
                }
                else
                {
                    obj = @object as GameObject;
                }
                if (obj != null)
                {
                    objs = obj.GetComponents<Component>().Select(component => (Object)component).ToList();
                    objs.Insert(0, obj);
                }
                else
                {
                    objs = new List<Object>();
                    objs.Add(@object);
                }
            }
            return objs;
        }
        // 对象是否包含该组件包括自身
        private bool HasComponent(Object obj)
        {
            return GetComponents().Any(go => go == obj);
        }
        private void OnFieldNameChange()
        {
            if (!Regex.IsMatch(FieldName, @"^[a-zA-Z_\u4e00-\u9fa5][a-zA-Z0-9_\u4e00-\u9fa5]*$"))
            {
                FieldName = "";
            }
        }

        [OnInspectorInit]
        private void CreateData()
        {
            // 开始显示初始化
            OnObjectChange();
        }
        #endregion
#endif
    }
    /// <summary>
    /// 一般类型集合
    /// </summary>
    [Serializable]
    public class ComponentDataValueCollectionItem
    {
        #region 对象类型
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.Bool)]
        public List<bool> boolValues;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.Int)]
        public List<int> intValues;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.Float)]
        public List<float> floatValues;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.Char)]
        public List<char> charValues;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.String)]
        public List<string> stringValues;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.Vector2)]
        public List<Vector2> vector2Values;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.Vector3)]
        public List<Vector3> vector3Values;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.Vector4)]
        public List<Vector4> vector4Values;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.Color)]
        public List<Color> colorValues;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.Gradient)]
        public List<Gradient> gradientValues;
        [VerticalGroup("其他类型"), HideLabel, LabelWidth(22), ShowIf("enumValues", EnumValue.AnimationCurve)]
        public List<AnimationCurve> animationcurveValues;

        [HorizontalGroup("其他类型/HorizontalGroup")]
        [HideLabel, ReadOnly]
        public string type = "类型";
        [HorizontalGroup("其他类型/HorizontalGroup")]
        [HideLabel, OnValueChanged("OnEnumValueChange")]
        public EnumValue enumValues;
        #endregion
        #region 生成字段
        [VerticalGroup("生成字段"), LabelText("字段名称:"), LabelWidth(60), Delayed, OnValueChanged("OnFieldNameChange")]
        public string FieldName;
        [VerticalGroup("生成字段"), LabelText("注释描述:"), LabelWidth(60)]
        public string Description;
        #endregion
#if UNITY_EDITOR
        #region 按钮
        //[TableColumnWidth(70, Resizable = false)]
        //[VerticalGroup("按钮")]
        //[Button("测试")]
        //private void Test()
        //{

        //}
        #endregion
        #region 事件
        private void OnEnumValueChange()
        {
            Type _type = enumValues.GetType();
            string name = Enum.GetName(_type, enumValues);
            FieldInfo field = _type.GetField(name);
            EnumValueTypeAttribute attribute = Attribute.GetCustomAttribute(field, typeof(EnumValueTypeAttribute)) as EnumValueTypeAttribute;
            type = $"List<{attribute.TypeFullName}>";
            ClearOtherValues();
        }
        // 清空没有选择的字段集合
        private void ClearOtherValues()
        {
            foreach (var type in this.GetType().GetFields())
            {
                ShowIfAttribute show = type.GetCustomAttribute<ShowIfAttribute>(true);
                if (show != null && (EnumValue)show.Value != enumValues)
                {
                    type.SetValue(this, default);
                }
            }
        }
        private void OnFieldNameChange()
        {
            if (!Regex.IsMatch(FieldName, @"^[a-zA-Z_\u4e00-\u9fa5][a-zA-Z0-9_\u4e00-\u9fa5]*$"))
            {
                FieldName = "";
            }
        }
        [OnInspectorInit]
        private void CreateData()
        {
            // 开始显示初始化
            OnEnumValueChange();
        }
        #endregion
#endif
    }
    /// <summary>
    /// Unity 对象集合
    /// </summary>
    [Serializable]
    public class ComponentDataReferenceCollectionItem
    {
        private EnumObject enumObject = EnumObject.None;
        #region 对象类型
        [VerticalGroup("对象类型"), LabelWidth(22)]
        [HideLabel, ListDrawerSettings(HideAddButton = true)]
        public List<Object> @objects;

        [HorizontalGroup("对象类型/HorizontalGroup")]
        [HideLabel, ReadOnly]
        public string type = "类型";
        [HorizontalGroup("对象类型/HorizontalGroup")]
        [HideLabel]
        [ValueDropdown("GetComponents"), Required("请选择一个对象!")]
        public Object @component;
        [HideInInspector]
        public List<Object> components = new List<Object>();
        #endregion
        #region 生成字段
        [VerticalGroup("生成字段"), LabelText("字段名称:"), LabelWidth(60), Delayed, OnValueChanged("OnFieldNameChange")]
        public string FieldName;
        [VerticalGroup("生成字段"), LabelText("注释描述:"), LabelWidth(60)]
        public string Description;
        #endregion
#if UNITY_EDITOR
        #region 按钮
        [TableColumnWidth(70, Resizable = false)]
        [VerticalGroup("按钮"), Button("扩充")]
        private void Add()
        {
            @objects.Add(null);
        }
        [VerticalGroup("按钮"), Button("清空Null")]
        private void ClearNull()
        {
            @objects.RemoveAll(item => item == null); // 删除空引用
        }
        #endregion
        #region 事件
        private void OnObjectsChange()
        {
            enumObject = EnumObject.None;
            if (@objects != null)
            {
                foreach (var obj in @objects)
                {
                    if (obj == null)
                    {
                        type = "List<Null>";
                        @component = null;
                        enumObject = EnumObject.None;
                        return;
                    }
                    else
                    {
                        var t = obj.GetType();
                        // 判断是否是Editor 对象类型
                        if (t.FullName.Contains("UnityEditor"))
                        {
                            type = "List<Null>";
                            @component = null;
                            enumObject = EnumObject.EditorObject;
                            return;
                        }
                        else
                        {
                            // 判断是否是预制件对象
                            if (PrefabUtility.GetPrefabAssetType(obj) != PrefabAssetType.NotAPrefab)
                            {
                                enumObject = EnumObject.PrefabObject;
                            }
                            else if (enumObject != EnumObject.PrefabObject)
                            {
                                enumObject = EnumObject.UnityObject;
                            }
                        }
                    }
                }
            }
        }
        private void OnComponentChange()
        {
            components.Clear();
            if (@component != null)
            {
                Type T = @component.GetType();
                if (T == typeof(GameObject))
                {
                    foreach (var obj in @objects)
                    {
                        components.Add(obj as GameObject);
                    }
                }
                else
                {
                    foreach (var obj in @objects)
                    {
                        GameObject go = obj as GameObject;
                        components.Add(go.GetComponent(T));
                    }
                }
                type = $"List<{T.FullName}>";
            }
        }
        private void OnFieldNameChange()
        {
            if (!Regex.IsMatch(FieldName, @"^[a-zA-Z_\u4e00-\u9fa5][a-zA-Z0-9_\u4e00-\u9fa5]*$"))
            {
                FieldName = "";
            }
        }

        // 返回选中对象组件集合
        private IEnumerable<Object> GetComponents()
        {
            List<Object> objs = null;
            if (enumObject == EnumObject.PrefabObject)
            {
                // 预制件对象 只包含 GameObject
                objs = new List<Object>();
                Object firstObj = @objects[0];
                objs.Add(firstObj);
            }
            else if (enumObject == EnumObject.UnityObject)
            {
                // 场景对象包含 Gameobject 和 Component
                GameObject firstObj = @objects[0] as GameObject;
                objs = new List<Object>();
                objs.Add(firstObj);
                // 查找其他组件与第一个对象共有的组件
                foreach (var component in firstObj.GetComponents<Component>())
                {
                    bool isAdd = true;
                    Type t = component.GetType();
                    for (int i = 1; i < @objects.Count; i++)
                    {
                        GameObject go = @objects[i] as GameObject;
                        var types = go.GetComponents<Component>().Convert<Type>(obj => obj.GetType());
                        if (!types.Contains(t))
                        {
                            isAdd = false;
                            break;
                        }
                    }
                    if (isAdd)
                    {
                        objs.Add(component);
                    }
                }
            }
            return objs;
        }
        #endregion
        public void Update()
        {
            OnObjectsChange();
            OnComponentChange();
        }
#endif
    }
}